#pragma once
#include "tcpserver.hpp"
#include "Addr.hpp"
#include "Util.hpp"
#include <sstream>
#include "mytcp.hpp"
#include <functional>
std::string gspace = " ";
std::string gline = "\r\n";
std::string gkv = ": ";
std::string root = "./wwwroot";
std::string homepage = "/index.html";
class HttpRequest
{
public:
    HttpRequest()
        : _version("HTTP/1.0"), _is_interact(false), _args("空args")
    {
    }
    // 序列化
    std::string Serialization(std::string &message)
    {
        return std::string();
    }
    // 获取请求行的函数
    std::string RequestLine(std::string &message)
    {
        // 找到第一个换行符前边的内容就是请求行
        int pos = message.find(gline);
        if (pos == std::string::npos)
        {
            // 没找到,完全不是一个完整报文
            LOG(LogLevel::ERROR) << "不是一个完整报文,不存在请求行";
            return std::string();
        }
        // 找到了换行符的下标
        std::string requestline = message.substr(0, pos);
        return requestline;
    }
    // 获取url
    std::string GetUrl()
    {
        return _url;
    }
    std::string GetArgs()
    {
        return _args;
    }
    bool IsInteract()
    {
        return _is_interact;
    }
    // 反序列化
    bool Deserialization(std::string &message)
    {
        // 首先我们要获取报文的请求行
        std::string requestline = RequestLine(message);
        // 获取了请求行之后我们就需要把请求行+分隔符gline一起删除掉
        message.erase(0, requestline.size() + gline.size());
        // 把拿到的请求行的三个参数取出,使用stringstream
        std::stringstream ss(requestline);
        ss >> _method >> _url >> _version;
        // 此时我们需要分析url是否存在,以及存在后的处理
        if (_url == "/")
        {
            _url = root + homepage;
        }
        else
        {
            _url = root + _url;
        }
        // 交互型url:ip:8080/login?password=...&username=...
        std::string sep = "?";
        int pos = _url.find(sep);
        if (pos != std::string::npos)
        {
            // 是交互型url
            _is_interact = true;
            _args = _url.substr(pos + sep.size()); // password=...&username=...
            _url = _url.substr(0, pos);            // ip:8080/login
        }
        std::cout << "自己的:" << _method << " " << _url << " " << _version << " " << _args << std::endl;
        return true;
    }
    ~HttpRequest()
    {
    }

private:
    std::string _method;                                   // 请求方法
    std::string _url;                                      // url超链接
    std::string _version;                                  // 版本
    std::string _blankline;                                // 空行
    std::string _texts;                                    // 有效载荷文本
    std::unordered_map<std::string, std::string> _headers; // 响应报头
    std::string _args;                                     // 参数
    bool _is_interact;                                     // 是否为交互型
};
class HttpResopnse
{
public:
    HttpResopnse()
        : _version("HTTP/1.0")
    {
    }
    // 序列化
    std::string Serialization()
    {
        std::string statu_line = _version + gspace + std::to_string(_code) + gspace + _desc + gline; // 状态行
        std::string resp_line;                                                                       // 应答报头
        for (auto header : _headers)
        {
            std::string line = header.first + gkv + header.second + gline; // 单行应答报头
            resp_line += line;
        }
        // 最后的序列化结果就是一个字符串
        std::string serialiazation = statu_line + resp_line + gline + _texts;
        return serialiazation;
    }
    void SetTargetFile(std::string &target)
    {
        _target = target;
    }
    void SetCode(int code) // 设定code的值再根据code设定_desc
    {
        _code = code;
        switch (_code)
        {
        case 200:
            _desc = "OK";
            break;
        case 404:
            _desc = "Not Found";
            break;
        case 302:
            _desc = "See Other";
        case 301:
            _desc = "Moved Permanently";
        default:
            break;
        }
    }
    // 找后缀,以确定报头:Content-Type的值
    std::string Uri2Suffix(std::string target)
    {
        // 从后往前找"."
        int pos = target.rfind(".");
        if (pos == std::string::npos)
        {
            // 没找到
            
            return "text/html";
        }
        // 找到了
        std::string Suffix = target.substr(pos);
        if (Suffix == ".html" || Suffix == ".htm")
        {
            return "text/html";
        }
        else if (Suffix == ".jpg")
        {
            return "image/jpeg";
        }
        else if (Suffix == ".png")
        {
            return "image/png";
        }
        else
        {
            return "";
        }
    }
    bool MakeResponse()
    {
        if (_target == "./wwwroot/favicon.ico")
        {
            // 直接忽略该请求
            std::cout << "_target == ./wwwroot/favicon.ico" << std::endl; //你的这里没有写什么东西哈
            return false;
        }
        if (_target == "./wwwroot/redir.html")
        {
            // 重定向到腾讯官网
            SetCode(302);
            SetHeader("Location", "https://www.qq.com/");
            return true;
        }
        bool ret = Util().ReadFile(_target, &(_texts));
        if (!ret)
        {
            // 打开文件失败
            LOG(LogLevel::FATAL) << "文件打开失败";
            SetCode(404);
            _target = root + "/404.html";
            Util().ReadFile(_target, &(_texts));
            int filesize = Util().FileSize(_target);
            // SetHeader("Content-Length",to_string(filesize));
            // std::cout<<"Content-Length:"<<filesize<<std::endl;
            std::string Suffix = Uri2Suffix(_target);
            SetHeader("Content-Type", Suffix);
        }
        else
        {
            // 打开文件成功
            SetCode(200);
            int filesize = Util().FileSize(_target);
            // SetHeader("Content-Length",to_string(filesize));
            // std::cout<<"Content-Length:"<<filesize<<std::endl;
            std::string Suffix = Uri2Suffix(_target);
            SetHeader("Content-Type", Suffix);
        }
        return true;
    }
    void SetText(std::string text)
    {
        _texts = text;
    }
    // 创建报头
    void SetHeader(std::string key, std::string value)
    {
        auto header = _headers.find(key);
        if (header == _headers.end())
        {
            // 没有找到对应的key值,则insert
            _headers.insert(std::make_pair(key, value));
        }
        return;
    }
    // 反序列化
    bool Deserialization(std::string &message)
    {
        return true;
    }
    ~HttpResopnse()
    {
    }



public:
    std::string _version;                                  // 版本
    int _code;                                             // 状态码
    std::string _desc;                                     // 状态码描述
    std::string _blankline;                                // 空行
    std::string _texts;                                    // 有效载荷文本
    std::unordered_map<std::string, std::string> _headers; // 响应报头
    std::string _target;                                   // 目标资源
};
// 对应我们的服务
using http_func_t = function<void(HttpRequest &req, HttpResopnse &resp)>;
class Http
{
public:
    Http(uint16_t port)
        : _tcpsvr(std::make_unique<tcpserver>(port))
    {
    }
    void Start()
    {
        _tcpsvr->Start([this](shared_ptr<Socket> &sock, Addr &client)
                       { this->GetHttpHandler(sock, client); });
    }
    // 向_headers中加入服务函数
    void SetHeader(std::string name, http_func_t func)
    {
        // 寻找name的服务函数是否存在
        std::string key = root + name;
        auto iter = _headers.find(key);
        if (iter != _headers.end())
        {
            // 该方法存在
            return;
        }
        // 该方法不存在,则加入
        _headers.insert(std::make_pair(key, func));
        std::cout << "##############服务函数载入成功##################" << std::endl;
        std::cout << "##############服务函数的key为:"<<key<<"##################" << std::endl;
    }
    void GetHttpHandler(shared_ptr<Socket> &sock, Addr &client)
    {
        std::string message;
        int n = sock->Recv(&message);
        std::cout << message << std::endl;
        // hr.Serialization(message);
        if (n > 0)
        {
            // 首先要验证报文的完整性:
            // 1,如果我们读到了空行,那说明我们就读到了完整的报头
            // 2,报头中有一个content-length,用于表示有效载荷的长度
            // 对收到的消息message进行反序列化
            HttpRequest hr;
            hr.Deserialization(message);
            HttpResopnse hp;
            // 判断是否需要交互
            if (hr.IsInteract())
            {
                // 需要交互
                std::cout << "################该方法需要交互###################" << std::endl;
                std::cout<<"##################hr.GetUrl:"<<hr.GetUrl()<<"#####################"<<std::endl;
                if (_headers.find(hr.GetUrl()) == _headers.end())
                {
                    // 不存在该方法,404
                    // std::cout << "################该交互方法不存在###################" << std::endl;
                    // hp.SetCode(302);
                    // hp.SetHeader("Location", "http://121.36.21.33:8080/404.html");
                }
                else
                {
                    // 该方法存在
                    std::cout << "################该交互方法存在,开始交互###################" << std::endl;
                    _headers[hr.GetUrl()](hr, hp); // 执行服务函数
                }
                std::string serialization = hp.Serialization();
                std::cout << "################+++++++++++++++++++++++###################" << std::endl;
                std::cout << serialization << std::endl;

                std::cout << "################+++++++++++++++++++++++###################" << std::endl;
                // 序列化成功,将结果发送
                sock->Send(serialization);
            }
            else
            {
                // 不需要交互
                std::cout << "################该方法不需要交互###################" << std::endl;
                //  文本内容我们就以文件的形式打开
                std::string filename = hr.GetUrl();
                hp.SetTargetFile(filename);
                if (hp.MakeResponse())
                {
                    // 文件打开成功
                    //  赋值完成后将response里的内容序列化
                    std::string serialization = hp.Serialization();
                    // 序列化成功,将结果发送
                    sock->Send(serialization);
                }
            }
        }
    }
    ~Http()
    {
    }

private:
    std::unique_ptr<tcpserver> _tcpsvr;
    // 用于储存服务方法
    std::unordered_map<std::string, http_func_t> _headers;
};